package fr.resasante.spring3.controller;

import java.security.Principal;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import fr.resasante.ejb.dto.User;
import fr.resasante.ejb.service.UserServiceRemote;
import fr.resasante.ejb.utils.EjbResponse;
import fr.resasante.exception.ApplicationException;
import fr.resasante.spring3.controller.common.ControllerAbstract;
import fr.resasante.spring3.controller.view.CommonView;
import fr.resasante.spring3.controller.view.SettingsView;
import fr.resasante.spring3.form.UserForm;
import fr.resasante.spring3.security.UserImpl;
import fr.resasante.spring3.security.UserServiceImpl;
import fr.resasante.utils.CommonUtils;
import fr.resasante.utils.DepartmentsUtils;
import fr.resasante.utils.ServicesUtils;

/**
 * Controller for settings
 * 
 * @author GEFFROY-DE-VILLEBLAN
 * 
 */
@Controller
@SessionAttributes
public class SettingsController extends ControllerAbstract {
	/**
	 * Logger for the class
	 */
	private static final Logger logger = Logger.getLogger(SettingsController.class.getName());

	/**
	 * Change the password of the user
	 * 
	 * @param userForm
	 *            The professional user object
	 * @param request
	 *            The request
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(
			value = "/change/password",
			method = RequestMethod.POST)
	public ModelAndView changePassword(UserForm userForm, HttpServletRequest request)
			throws ApplicationException {
		final EjbResponse ejbResponse = new EjbResponse();
		try {
			final User user = new User();
			BeanUtils.copyProperties(user, userForm);
			// Call the service for adding an user
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			final boolean result = service.changePassword(user);
			// Check the errors from service
			if (!result) {
				ejbResponse.addError("error.calling.ejb");
				return SettingsView.getInstance().getPasswordChangeWithErrorView(userForm,
						ejbResponse);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			return SettingsView.getInstance().getPasswordChangeWithErrorView(userForm,
					ejbResponse);
		}
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.change.password");
	}

	/**
	 * Change the address of the user
	 * 
	 * @param userForm
	 *            The professional user object
	 * @param request
	 *            The request
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(
			value = "/change/address",
			method = RequestMethod.POST)
	@PreAuthorize("isAuthenticated()")
	public ModelAndView changeAddress(UserForm userForm, HttpServletRequest request,
			Principal principal) throws ApplicationException {
		final EjbResponse ejbResponse = new EjbResponse();
		final User user = new User();
		try {
			BeanUtils.copyProperties(user, userForm);
			// Call the service for adding an user
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			final boolean result = service.changeAddress(user);
			// Check the errors from service
			if (!result) {
				ejbResponse.addError("error.calling.ejb");
				return SettingsView.getInstance().getAddressChangeWithErrorView(userForm,
						ejbResponse);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			return SettingsView.getInstance().getAddressChangeWithErrorView(userForm,
					ejbResponse);
		}
		updateUserInSession(request, (Authentication) principal, user);
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.change.address");
	}

	@Autowired
	AuthenticationManager authenticationManager;

	private void updateUserInSession(HttpServletRequest request,
			Authentication initialAuthentication, User user) {
		UserServiceImpl userServiceImpl = new UserServiceImpl();
		UserImpl userImpl = (UserImpl) userServiceImpl.loadUserByUsername(user.getUsername());

		userImpl.setPostalAddress(user.getPostalAddress());
		userImpl.setPostalCode(user.getPostalCode());
		userImpl.setPostOfficeBox(user.getPostOfficeBox());
		userImpl.setCity(user.getCity());
		userImpl.setDepartmentCode(user.getDepartmentCode());
		userImpl.setDepartmentLabel(user.getDepartmentLabel());

		Authentication authToken = new UsernamePasswordAuthenticationToken(userImpl, null,
				userImpl.getAuthorities());
		SecurityContext securityContext = SecurityContextHolder.getContext();
		securityContext.setAuthentication(authToken);
	}

	/**
	 * Show a form for changing password
	 * 
	 * @param request
	 *            The request
	 * @param response
	 *            The response
	 * @param principal
	 *            The principal
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(
			value = "/settings/password",
			method = RequestMethod.GET)
	@PreAuthorize("isAuthenticated()")
	public ModelAndView showPasswordChange(HttpServletRequest request,
			HttpServletResponse response, Principal principal, Locale locale)
			throws ApplicationException {
		UserForm userForm = setUserFormFromSession(response, principal);
		if (null == userForm) {
			return forbidden(response);
		}
		// If everything goes fine
		final ModelAndView modelAndView = SettingsView.getInstance().getPasswordChangeView(
				userForm);
		final String message = messageSource.getMessage("label.change.password", null, locale);
		modelAndView.addObject("pageTitle", message);
		return modelAndView;
	}

	/**
	 * Show a form for changing password
	 * 
	 * @param request
	 *            The request
	 * @param response
	 *            The response
	 * @param salt
	 *            The salt key
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(
			value = "/settings/password",
			method = RequestMethod.GET,
			params = { "salt" })
	@PreAuthorize("isAnonymous()")
	public ModelAndView showPasswordChange(HttpServletRequest request,
			HttpServletResponse response, @RequestParam(
					value = "salt") String salt) throws ApplicationException {
		User user = null;
		final UserForm userForm = new UserForm();
		try {
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			user = service.getUserBySalt(salt);
			if (null == user) {
				return forbidden(response);
			} else {
				BeanUtils.copyProperties(userForm, user);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			return forbidden(response);
		}
		// If everything goes fine
		return SettingsView.getInstance().getPasswordChangeView(userForm);
	}

	/**
	 * Set a user form object from session
	 * 
	 * @param response
	 *            The response
	 * @param principal
	 *            The principal
	 * @return The userForm object
	 */
	private UserForm setUserFormFromSession(HttpServletResponse response, Principal principal) {
		UserImpl user;
		final UserForm userForm = new UserForm();
		try {
			user = (UserImpl) ((Authentication) principal).getPrincipal();
			if (null == user) {
				return null;
			} else {
				BeanUtils.copyProperties(userForm, user);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			return null;
		}
		return userForm;
	}

	/**
	 * Displays a form for changing address
	 * 
	 * @param request
	 *            The request
	 * @param response
	 *            The response
	 * @param principal
	 *            The principal
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(
			value = "/settings/address",
			method = RequestMethod.GET)
	@PreAuthorize("isAuthenticated()")
	public ModelAndView showAddressChange(HttpServletRequest request,
			HttpServletResponse response, Principal principal, Locale locale)
			throws ApplicationException {
		UserForm userForm = setUserFormFromSession(response, principal);
		if (null == userForm) {
			return forbidden(response);
		}
		// If everything goes fine
		final ModelAndView modelAndView = SettingsView.getInstance().getAddressChangeView(
				userForm);
		final String message = messageSource.getMessage("label.change.address", null, locale);
		modelAndView.addObject("departmentList", DepartmentsUtils.getInstance()
				.getAllDepartments());
		modelAndView.addObject("pageTitle", message);
		return modelAndView;
	}
}
